using StackCalc.Instructions;

namespace StackCalc.Parsing.ParsingUnits
{
	public class BracedExpressionParser : BaseParsingUnit<BracedExpression>
	{
		protected override bool CanParseImplementation(string input)
		{
			// starts with '['
			return input[0] == '[';
		}

		protected override bool HasSyntaxErrorImplementation(string input)
		{
			int numOpenBraces = 0;

			// syntax is only correct if there are as many closed as open bracers
			foreach (char c in input)
			{
				if (c == '[')
				{
					numOpenBraces++;
				}
				else if (c == ']')
				{
					numOpenBraces--;

					if (numOpenBraces == 0)
					{
						break;
					}
				}
			}

			// syntax error is present if we can parse but the number of braces does not match
			return numOpenBraces != 0;
		}

		public override string GetErrorDescription()
		{
			return "Number of closing braces incorrect!";
		}

		protected override BracedExpression ParseImplementation(string input)
		{
			int numOpenBracers = 1;
			input = input.Remove(0, 1);
			string parsedString = string.Empty;

			// syntax is only correct if there are as many closed as open bracers
			foreach (char c in input)
			{
				// add character
				parsedString += c;

				if (c == '[')
				{
					numOpenBracers++;
				}
				else if (c == ']')
				{
					numOpenBracers--;

					if (numOpenBracers == 0)
					{
						break;
					}
				}
			}

			return new BracedExpression(parsedString.Remove(parsedString.Length-1));
		}

		protected override string TrunkateImplementation(string input)
		{
			int numOpenBracers = 1;
			input = input.Remove(0, 1);
			int charactersToTrunkate = 0;

			// syntax is only correct if there are as many closed as open bracers
			foreach (char c in input)
			{
				charactersToTrunkate++;

				if (c == '[')
				{
					numOpenBracers++;
				}
				else if (c == ']')
				{
					numOpenBracers--;

					if (numOpenBracers == 0)
					{
						break;
					}
				}
			}

			return input.Remove(0, charactersToTrunkate);
		}
	}
}
